import LogFactory from "../log/LogFactory";
import {MessageInstance} from "antd/es/message/interface";
import {NavigateFunction} from "react-router/dist/lib/hooks";
import {AsyncThunkAction, ThunkDispatch} from "@reduxjs/toolkit";
import {AsyncThunkConfig} from "@reduxjs/toolkit/src/createAsyncThunk";
import {Result} from "../type/Result";
import {ADD_FAILED, ADD_SUCCESS, UPDATE_FAILED, UPDATE_SUCCESS} from "../constant/HintMessage";

/**
 * 全局处理类,处理全局的一些事件操作
 */
const log = LogFactory.getLog("GlobalHandler") ;
class GlobalHandler{
    private static readonly instance = new GlobalHandler() ;
    private message: MessageInstance | undefined ;
    private navigate: NavigateFunction | undefined ;
    private dispatch: ThunkDispatch<any, any, any> | undefined ;

    private static flagWarn = false ;

    /**
     * 私有构造
     */
    private constructor() {
    }


    /**
     * 获取全局处理类的实例
     */
    public static getInstance(): GlobalHandler {
        return this.instance ;
    }

    /**
     * 设置全局消息提示工具
     * @param message 消息提示工具
     */
    public setMessage(message: MessageInstance) {
        // log.debug("设置全局消息提示工具") ;
        this.message = message ;
    }

    /**
     * 获取全局消息提示工具
     */
    public getMessage(): MessageInstance {
        if (this.message === void 0){
            log.error("全局变量message未初始化") ;
            throw new Error("全局变量message未初始化") ;
        }
        return this.message ;
    }

    /**
     * 判断全局路由是否加载
     * @return true:未加载 false:已加载
     */
    public isNavigateLoaded(): boolean {
        return this.navigate === void 0 ;
    }

    /**
     * 判断全局dispatch是否加载
     */
    public isDispatchLoaded(): boolean {
        return this.dispatch === void 0 ;
    }


    /**
     * 设置全局路由跳转工具
     * @param navigate 路由跳转工具
     */
    public setNavigate(navigate: NavigateFunction) {
        // log.debug("设置全局路由跳转工具") ;
        this.navigate = navigate ;
    }

    /**
     * 设置全局dispatch,redux调度工具
     */
    public setDispatch(dispatch: ThunkDispatch<any, any, any>) {
        // log.debug("设置全局dispatch,redux调度工具") ;
        this.dispatch = dispatch ;
    }

    /**
     * 获取全局dispatch,redux调度工具
     */
    public getDispatch(): ThunkDispatch<any, any, any> {
        if (this.dispatch === void 0){
            log.error("全局变量dispatch未初始化") ;
            throw new Error("全局变量dispatch未初始化") ;
        }
        return this.dispatch ;
    }

    /**
     * 全局执行异步action的Dispatch执行方法
     * @param action 异步action[AsyncThunkAction<T, number, AsyncThunkConfig>]
     * @return 返回异步action的执行结果
     */
    public async executeDispatchAsync<T>(action: AsyncThunkAction<T, number, AsyncThunkConfig>): Promise<T> {
        // log.debug("执行全局dispatch异步代理 ==> action: " , action) ;
        return await this.getDispatch()(action).unwrap() ;
    }

    private async executeAsyncAction<R,P>(asyncAction: AsyncThunkAction<R, P, AsyncThunkConfig>): Promise<R> {
        return await this.getDispatch()(asyncAction).unwrap() ;
    }

    /**
     * 全局执行异步添加数据action,调用此方法的异步action的反回值必须是Result<T>类型
     * 此方法添加成功后会显示成功消息,并且跳转到上一个页面
     * @param asyncAction 需要执行的异步action [AsyncThunkAction<R, P, AsyncThunkConfig>] R:返回结果类型 P:参数类型
     * @return 返回异步action的执行结果
     */
    public async executeAddAsyncAction<R,P>(asyncAction: AsyncThunkAction<Result<R>, P, AsyncThunkConfig>): Promise<Result<R>> {
        const result = await this.getDispatch()(asyncAction).unwrap() ;
        if (result.success){
            this.getMessage().success(ADD_SUCCESS) ;
            this.getNavigate()(-1) ;
        }else {
            this.getMessage().error(ADD_FAILED) ;
        }
        return result ;
    }

    /**
     * 全局执行异步修改数据action,调用此方法的异步action的反回值必须是Result<T>类型
     * 此方法添加成功后会显示成功消息,并且跳转到上一个页面
     * @param asyncAction 需要执行的异步action [AsyncThunkAction<R, P, AsyncThunkConfig>] R:返回结果类型 P:参数类型
     * @return 返回异步action的执行结果
     */
    public async executeUpdateAsyncAction<P>(asyncAction: AsyncThunkAction<P, P, AsyncThunkConfig>): Promise<P | null> {
        const result = await this.getDispatch()(asyncAction).unwrap() ;
        if (result === null){
            this.getMessage().error(UPDATE_FAILED) ;
        }else {
            this.getMessage().success(UPDATE_SUCCESS) ;
            this.getNavigate()(-1) ;
        }
        return result ;
    }


    /**
     * 全局路由跳转
     * @param path 跳转路径
     * @param replace 是否替换当前路径
     * @param state 路由状态 { [key: string]: any}
     */
    public navigateTo(path: string,replace?: boolean,state?: { [key: string]: any}) {
        this.getNavigate()(path, {replace,state}) ;
    }

    /**
     * 获取全局dispatch,redux调度工具
     */
    public getNavigate(): NavigateFunction {
        if (this.navigate === void 0){
            log.error("全局变量navigate未初始化") ;
            throw new Error("全局变量navigate未初始化") ;
        }
        return this.navigate ;
    }

    /**
     * 发送全局成功消息
     * @param messageInfo 消息内容
     * @param duration 显示消息的持续时间,默认3秒
     * @param callback 回调函数
     */
    public sendSuccessMessage(messageInfo: string,duration?: number,callback?: () => void) {
        this.getMessage().success(messageInfo,duration).then(callback,) ;
    }

    /**
     * 发送全局一般类型(提醒)消息
     * @param messageInfo 消息内容
     * @param duration 显示消息的持续时间,默认3秒
     * @param callback 回调函数
     */
    public sendInfoMessage(messageInfo: string,duration?: number,callback?: () => void) {
        this.getMessage().info(messageInfo,duration).then(callback,) ;
    }

    /**
     * 发送全局警告消息
     * @param messageInfo 消息内容
     * @param duration 显示消息的持续时间,默认3秒
     * @param callback 回调函数
     */
    public sendWarningMessage(messageInfo: string,duration?: number,callback?: () => void) {
        if (GlobalHandler.flagWarn){
            log.debug("警告消息正在显示中,不再重复显示") ;
            return ;
        }
        GlobalHandler.flagWarn = true ;
        this.getMessage().warning(messageInfo,duration).then(callback,) ;
        setTimeout(() => {
            GlobalHandler.flagWarn = false ;
        },2000) ;
    }
    /**
     * 发送全局错误消息
     * @param messageInfo 消息内容
     * @param duration 显示消息的持续时间,默认3秒
     * @param callback 回调函数
     */
    public sendErrorMessage(messageInfo: string,duration?: number,callback?: () => void) {
        this.getMessage().error(messageInfo,duration).then(callback,) ;
    }

}


export default GlobalHandler ;